#include "BlockQ.h"

BlockQ* blockq_create(void) {
	BlockQ* q = (BlockQ*) calloc(1, sizeof(BlockQ));	

	pthread_cond_init(&q->not_empty, NULL);
	pthread_cond_init(&q->not_full, NULL);
	pthread_mutex_init(&q->mutex, NULL);
	return q;
}

void blockq_destroy(BlockQ* q) {
	pthread_mutex_destroy(&q->mutex);
	pthread_cond_destroy(&q->not_full);
	pthread_cond_destroy(&q->not_empty);
	free(q);
}

bool blockq_empty(BlockQ* q) {
	pthread_mutex_lock(&q->mutex);
	int size = q->size;
	pthread_mutex_unlock(&q->mutex);
	return size == 0;
}

bool blockq_full(BlockQ* q) {
	pthread_mutex_lock(&q->mutex);
	int size = q->size;
	pthread_mutex_unlock(&q->mutex);
	return size == MAXLEN;
}

// 重点
void blockq_push(BlockQ* q, E val) {
	pthread_mutex_lock(&q->mutex);
	while (q->size == MAXLEN) {
		// 虚假唤醒现象
		pthread_cond_wait(&q->not_full, &q->mutex);
	} // q->size != MAXLEN
	
	q->elements[q->rear] = val;
	q->rear = (q->rear + 1) % MAXLEN;
	q->size++;
	// 条件：not_empty 成立
	pthread_cond_signal(&q->not_empty);
	pthread_mutex_unlock(&q->mutex);
}

E blockq_pop(BlockQ* q) {
	pthread_mutex_lock(&q->mutex);
	while (q->size == 0) {
		pthread_cond_wait(&q->not_empty, &q->mutex);
	} // q->size != 0
	E retval = q->elements[q->front];
	q->front = (q->front + 1) % MAXLEN;
	q->size--;
	// not_full条件成立
	pthread_cond_signal(&q->not_full);
	pthread_mutex_unlock(&q->mutex);
	return retval;
}

E blockq_peek(BlockQ* q) {
	pthread_mutex_lock(&q->mutex);
	while (q->size == 0) {
		pthread_cond_wait(&q->not_empty, &q->mutex);
	} // q->size != 0
	E retval = q->elements[q->front];
	pthread_mutex_unlock(&q->mutex);
	return retval;
}
